/**
 *@File:
 *
 *@Author:                                                                                                                                                                  
 *
 *@Create Time:
 *
 *@Last Modify
 *
 *@Description: 
 *
 */

#include <stdio.h>
#include <stdlib.h>

// 基类
struct base
{
	int num;
	void (*func)(struct base *pThis);	
};

// 派生类
struct derived
{
	struct base parent;
	int num;
	void (*func)(struct derived* pThis);
};


// 基类的函数base_func
static void base_func(struct base *pThis)
{
	printf("[%s:%s:%d] this is base::func, base::num = %d\n", __FILE__, __FUNCTION__, __LINE__, pThis->num);
} 

/*
派生类的函数derived_func
为了像 C++ 中一样通过类实例来访问成员函数，
必须将结构体内的函数指针的第一个参数定义为自身的指针，
在调用时传入函数指针所属的结构体实例。
这是因为 C 语言中不存在像 C++ 中那样的 this 指针，
如果我们不显式地通过参数提供，
那么在函数内部就无法访问结构体实例的其它成员。
*/
static void derived_func(struct derived *pThis)
{
	printf("[%s:%s:%d] this is derived::func, base::num = %d, derived::num = %d\n", __FILE__, __FUNCTION__, __LINE__, pThis->parent.num, pThis->num);
	pThis->parent.func(&pThis->parent);
} 


// new 一个基类对象 
struct base* new_base()
{
	struct base *pBase = (struct base *)malloc(sizeof(struct base));
	if (pBase != NULL)
	{
		pBase->num = 0;
		pBase->func = base_func;
	}

	return pBase;
}

// delete基类对象
void delete_base(struct base *pBase)
{
	if (pBase != NULL)
	{
		free(pBase);
		pBase = NULL;
	}
}


// new 一个派生类对象
struct derived* new_derived()
{
	struct derived *pDerived = (struct derived*)malloc(sizeof(struct derived));
	if (pDerived != NULL)
	{
		pDerived->num = 2;
		pDerived->func = derived_func;
	}

	return pDerived;
}

// delete 一个派生类对象
void delete_derived(struct derived *pDerived)
{
	if (pDerived != NULL)
	{
		free(pDerived);
		pDerived = NULL;
	}
}


// 测试基类的new和delete
void test1()
{
	struct base *pBase = new_base();
	if (pBase != NULL)
	{
		pBase->func(pBase);
	}

	delete_base(pBase);
}


// 测试派生类的new和delete
void test2()
{
	struct base stBase;
	stBase.func = base_func;
	stBase.num = 1;

	struct derived *pDerived = new_derived();
	if (pDerived != NULL)
	{
		pDerived->parent = stBase;
		pDerived->func(pDerived);
	}

	delete_derived(pDerived);
}


// 测试覆盖，通过将派生类的指针强制类型转换成基类的指针
void test3()
{
	struct base stBase;
	stBase.func = base_func;
	stBase.num = 1;

	struct derived *pDerived = new_derived();
	if (pDerived != NULL)
	{
		pDerived->parent = stBase;
		pDerived->func(pDerived);
		((struct base *)pDerived)->func((struct base *)pDerived);
		pDerived->parent.func((struct base *)pDerived);
	}

	delete_derived(pDerived);
}


int main(int argc, char *argv[])
{
	test1();
	test2();
	test3();
	return 0;
}
